import {createAsyncThunk, createSlice, PayloadAction} from "@reduxjs/toolkit";
import {AnyParams, AsyncSelectMethod, TableList, TablePage} from "@/common/httptypes";
import {Key} from "react";
import {ParseResponse} from "@/common/http";
import {util} from "@/common/util";


export class TableAction<RecordType> {
    key: string;
    rowKey: string;
    row?: RecordType;
    selectKeys: Key[];
    dataSource: RecordType[]
    mapping: AnyParams<any>

    constructor(key: string, rowKey: string, row: RecordType, selectKeys: Key[], dataSource: RecordType[]) {
        this.key = key;
        this.rowKey = rowKey;
        this.row = row
        this.selectKeys = selectKeys;
        this.dataSource = dataSource
        this.mapping = {}
        for (let i in this.dataSource) {
            let item = this.dataSource[i]
            // @ts-ignore
            this.mapping[item[this.rowKey]] = item;
        }
    }


    getList(): RecordType[] {
        if (this.selectKeys.length === 0) {
            return []
        } else {
            return this.selectKeys.map(p => this.mapping[p])
        }
    }

    getRow(): RecordType | undefined {
        if (this.row) {
            return this.row
        }
        if (this.selectKeys.length === 0) {
            return undefined
        } else {
            return this.mapping[this.selectKeys[0]]
        }
    }

    exists(keys: string[]): boolean {
        return keys.findIndex(p => p === this.key) !== -1
    }

    match(key: Key): boolean {
        return this.key === key
    }

    getTitle(mapping: { [key: string]: string }): { key: string, title: string } {
        return {key: this.key, title: mapping[this.key]}
    }

    isNil(): boolean {
        return this.key === "nil"
    }
}

export type HDataTableState<RecordType> = {
    table: {
        selectRowKeys: Key[];
        dataSource: TablePage<RecordType> | TableList<RecordType>;
        queryParams: AnyParams<any>,
        loading: boolean,
        pathname: string,
        action?: TableAction<RecordType>
        version: number
    }
}

export const asyncThunkSelectTableData = createAsyncThunk(
    'dataTable/selectData',
    async (action: { method: AsyncSelectMethod, params: AnyParams<any> }) => {
        const response = await action.method({params: action.params})
        const data = await ParseResponse(response)
        return data !== undefined ? data : {records: [], total: 0}
    }
);

export function createHDataTableInitialState(): HDataTableState<any>["table"] {
    return {
        dataSource: {
            records: [],
            total: 0,
        },
        selectRowKeys: [],
        queryParams: {},
        loading: false,
        version: 0,
        pathname: window.location.pathname,
    }
}

export const HDataTableSlice = createSlice({
    name: 'dataTable',
    initialState: {table: createHDataTableInitialState()},
    reducers: {
        setQueryParams(state, action: PayloadAction<AnyParams<any>>) {
            if (state.table.pathname !== window.location.pathname) {
                const newState = createHDataTableInitialState()
                newState.version += 1
                newState.queryParams = action.payload
                state.table = newState
            } else {
                state.table = {
                    ...state.table,
                    queryParams: {...state.table.queryParams, ...action.payload},
                    version: state.table.version + 1
                }
            }
        },
        setSelectedRowKeys(state, action: PayloadAction<Key[]>) {
            state.table.selectRowKeys = action.payload
        },
        onChangeRowKeys(state, action: PayloadAction<Key>) {
            let index = state.table.selectRowKeys.findIndex(p => p === action.payload)
            if (index === -1) {
                state.table.selectRowKeys.push(action.payload)
            } else {
                state.table.selectRowKeys.splice(index, 1)
            }
        }, resetAction(state) {
            state.table = {...state.table, action: undefined, version: state.table.version += 1}
        }, doAction(state, action: PayloadAction<{ action: string, rowKey: string, row?: any }>) {
            state.table.action = new TableAction(action.payload.action, action.payload.rowKey, action.payload.row
                , util.deepClone(state.table.selectRowKeys), util.deepClone(state.table.dataSource.records!))
        },
    }, extraReducers: (builder) => {
        builder
            .addCase(asyncThunkSelectTableData.pending, (state) => {
                state.table.loading = true;
            }).addCase(asyncThunkSelectTableData.fulfilled, (state, action) => {
            state.table = {...state.table, dataSource: action.payload, loading: false}
        });
    },
})


